/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <functional>
#include <map>
#include <mutex>
#include <atomic>
#include <vector>
#include <algorithm>

namespace El {
namespace Utils {

// 全局原子变量，用于生成回调句柄
extern std::atomic<int32_t> g_nextCallbackHandle;

template <typename R, typename... Args> class CallbackList {
public:
    using Callback = std::function<R(Args...)>;

    // Store handle along with callback and priority
    struct CallbackEntry {
        int32_t handle;
        Callback callback;
        int priority;
    };

    CallbackList() = default;

    int32_t Register(const Callback &callback, int32_t priority = 100)
    {
        if (callback == nullptr) {
            return -1; // Invalid callback
        }
        std::lock_guard<std::mutex> lock(mutex_);
        int32_t handle = g_nextCallbackHandle.fetch_add(1); // 使用全局变量并原子增加
        
        CallbackEntry new_entry = {handle, callback, priority};

        // Insert into sorted vector, maintaining order by priority
        auto it = std::lower_bound(
            sorted_callbacks_.begin(), sorted_callbacks_.end(), new_entry,
            [](const CallbackEntry& a, const CallbackEntry& b) {
                return a.priority < b.priority;
            });
        sorted_callbacks_.insert(it, new_entry);
        
        return handle;
    }

    void Unregister(int32_t handle)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = std::remove_if(
            sorted_callbacks_.begin(), sorted_callbacks_.end(),
            [handle](const CallbackEntry& entry) {
                return entry.handle == handle;
            });
        if (it != sorted_callbacks_.end()) {
            sorted_callbacks_.erase(it, sorted_callbacks_.end());
        }
    }

    auto InvokeAll(Args... args)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        // The vector is already sorted by priority.
        // Create a copy for safe iteration if callbacks might unregister themselves,
        // though current lock prevents concurrent modification.
        // For simplicity, direct iteration is used here, assuming callbacks don't modify the list during invocation.
        // If re-entrancy or self-unregistration is a concern, iterating a copy is safer:
        // std::vector<CallbackEntry> callbacks_to_invoke = sorted_callbacks_; 
        // for (const auto &entry : callbacks_to_invoke) { ... }

        if constexpr (std::is_same_v<R, void>) {
            for (const auto &entry : sorted_callbacks_) {
                entry.callback(std::forward<Args>(args)...);
            }
        } else if constexpr (std::is_same_v<R, bool>) {
            bool result = true;
            for (const auto &entry : sorted_callbacks_) {
                if (!entry.callback(std::forward<Args>(args)...)) {
                    result = false;
                    break;
                }
            }
            return result;
        } else {
            static_assert(std::is_same_v<R, void> || std::is_same_v<R, bool>, "Callback must return void or bool");
        }
    }

    bool IsEmpty() const
    {
        std::lock_guard<std::mutex> lock(mutex_);
        return sorted_callbacks_.empty();
    }

    void Clear()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        sorted_callbacks_.clear();
    }

private:
    std::vector<CallbackEntry> sorted_callbacks_;
    mutable std::mutex mutex_;
};

} // namespace Utils
} // namespace El